﻿namespace OpenAction
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Windows;

    using MEF_Test.Bricks;
    using MEF_Test.Contracts;

    // Important otherwise, only one instance of the OpenAction will ever be generated, and all the items cannot use the same instance of the action :
    // especially for the Presenter, becuse a visual cannot be more than once in the visual tree !
    [PartCreationPolicy(CreationPolicy.Shared)]
    [Export(typeof(INodeAction))]
    [ExportMetadata("Action", "Open")]
    public class OpenAction : NodeActionBase
    {
        #region Constants and Fields

        /// <summary>
        /// The providers which will do the actual work for the open command.
        /// </summary>
        /// <remarks>An open command is just an entry point : It also needs a provider containing the business logic to process the command. <see cref="_openProvider"/> is a list of all the discovered available providers.</remarks>
        private readonly IEnumerable<IOpenActionContextProvider> _openProvider;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="OpenAction"/> class.
        /// </summary>
        /// <param name="openContextProviderFactories">The open context provider factories.</param>
        [ImportingConstructor]
        public OpenAction([ImportMany(typeof(IOpenActionContextProviderFactory))] IEnumerable<Lazy<IOpenActionContextProviderFactory>> openContextProviderFactories)
        {
            _openProvider = from factory in openContextProviderFactories select factory.Value.Create();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the template.
        /// </summary>
        /// <value>The template.</value>
        public override DataTemplate Template
        {
            get
            {
                var source = new Uri("/OpenAction;component/Resources.xaml", UriKind.Relative);
                var resourceDictionary = new ResourceDictionary { Source = source };
                return (DataTemplate)resourceDictionary["OpenActionTemplate"];
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Gets the providers compatible with the specified <see cref="IBrowserNodeViewModel"/>.
        /// </summary>
        /// <param name="node">The <see cref="IBrowserNodeViewModel"/> browser node to find providers compatible with.</param>
        /// <returns>An enumerable of all the providers for this action which are compatible with the specified <see cref="IBrowserNodeViewModel"/>/></returns>
        public override IEnumerable<IActionContextProvider> GetCompatibleProviders(IBrowserNodeViewModel node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            var compatibleProviders = from provider in _openProvider
                                      where provider.Supports(node)
                                      select provider;
            
            return compatibleProviders;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Called when the execute command is activated.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        protected override object onExecuteActivateCommand(IBrowserNodeViewModel node)
        {
            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            IEnumerable<IActionContextProvider> compatibleProviders = GetCompatibleProviders(node);

            var provider = (IOpenActionContextProvider)node.SelectProvider(compatibleProviders, this);

            if (provider != null)
            {
                provider.Process(node);
            }

            return null;
        }

        #endregion
    }
}